package com.game.grid;

import java.util.LinkedList;
import javax.microedition.khronos.opengles.GL10;

import com.mcodesal.framework.audio.SoundManager;

import android.graphics.Point;

/**
 * Handles everything Maze related.  Generates, moves, and draws the Maze.
 * Checks for collisions with player.
 * 
 * @author Mostly Richie
 *
 */
public class MazeManager {
	
	private int screenSizeX, screenSizeY;
	private long mFrameTimer = -1;
	private int mMsPF = 400;
	private int mCurrentWallFrame = 0;
	private int mNumWallFrames = 3;
	
	//flag used for determining if the boxes have already
	//been changed by the program so that we don't have change the size of the boxes
	//multiple times.
	private boolean boxesChanged = false;
	private int playerBox = 0; //the box that the player is in at any given moment.
	private boolean sizeChangeOnScreen = false;
	
	private Box startBox; //start box variable, used more than once
	//box sizes constants
	public static final int LARGEST_BOX = 96;
	public static final int LARGE_BOX = 85;
	public static final int SMALL_BOX = 75;
	public static final int SMALLEST_BOX = 64;
	public int curBoxSize;
	private long lastTime = -1;
	
	//containers
	private LinkedList<Box[]> onScreen;  //list of all boxes[] onscreen
	private LinkedList<Box[]> offScreen; //list of all boxes[] offscreen
	private LinkedList<Box> collisionList; //list of all boxes that player can collide with.
	
	
	public MazeManager() {
		onScreen = new LinkedList<Box[]>();
    	offScreen = new LinkedList<Box[]>();
    	collisionList = new LinkedList<Box>();
    	
    	curBoxSize = LARGEST_BOX; //the game starts with the boxes being the largest size.
	}
	
	public void initialize(int width, int height) {
		screenSizeX = width;
		screenSizeY = height;
		
		startBox = new Box((width/2)-(curBoxSize/2),height-curBoxSize,curBoxSize);
		createBoxes();
	}
	/*
	 * Function for creating the boxes at the start of the game
	 * ----Creates the arrays for 6 straight up to allow the player
	 * ----to not have to immediately move.
	 */
	public void createBoxes() {
		
		Box[] temp = new Box[5];	
		startBox.initializeWestWall();
		startBox.initializeEastWall();
		temp[0] = startBox;
		temp[0].setUpBox();
		collisionList.add(temp[0]);
		onScreen.add(temp);
		
		
		Box row1 = new Box(startBox.getLeftSide(), startBox.getTopSide()-curBoxSize, curBoxSize);
		row1.initializeWestWall();
		row1.initializeEastWall();
		temp = new Box[5];
		temp[0] = row1;
		temp[0].setUpBox();
		collisionList.add(temp[0]);
		onScreen.add(temp);
		
		
		Box row2 = new Box(startBox.getLeftSide(), startBox.getTopSide()-curBoxSize*2, curBoxSize);
		row2.initializeWestWall();
		row2.initializeEastWall();
		temp = new Box[5];
		temp[0] = row2;
		temp[0].setUpBox();
		collisionList.add(temp[0]);
		onScreen.add(temp);
		
		
		Box row3 = new Box(startBox.getLeftSide(), startBox.getTopSide()-curBoxSize*3, curBoxSize);
		row3.initializeWestWall();
		row3.initializeEastWall();
		temp = new Box[5];
		temp[0] = row3;
		temp[0].setUpBox();
		collisionList.add(temp[0]);
		onScreen.add(temp);
		
		
		Box row4 = new Box(startBox.getLeftSide(), startBox.getTopSide()-curBoxSize*4, curBoxSize);
		row4.initializeWestWall();
		row4.initializeEastWall();
		temp = new Box[5];
		temp[0] = row4;
		temp[0].setUpBox();
		collisionList.add(temp[0]);
		onScreen.add(temp);
		
		
		Box row5 = new Box(startBox.getLeftSide(), startBox.getTopSide()-curBoxSize*5, curBoxSize);
		row5.initializeWestWall();
		row5.initializeEastWall();
		temp = new Box[5];
		temp[0] = row5;
		temp[0].setUpBox();
		collisionList.add(temp[0]);
		onScreen.add(temp);
		
		//all boxes onscreen for start are created
		
		Box row6 = new Box(startBox.getLeftSide(), 0, curBoxSize);
		row6.initializeWestWall();
		row6.initializeEastWall();
		temp = new Box[5];
		temp[0] = row6;
		temp[0].setUpBox();
		offScreen.add(temp);
		
		//creating randomly generated offscreen boxes
		for(int i = 0; i < 9;i++) {
			createOffScreenBoxes();
		}
	
	}
	
	/*
	 * Checks to see if the lowest box is still viewable
	 * If it isn't then it removes it 
	 * Also checks if a box needs to be added from the offscreen array to
	 * the onscreen array.
	 */
	public float checkBoxesOnScreen() {
		float returnValue = -10000;
		Box[] testBox = onScreen.getFirst(); //local test array.
		
		//checking if the first box in the onscreen array is offscreen.
		if(testBox[0].getTopSide() > screenSizeY+10) {
			for(Box b : onScreen.getFirst()) {
				if(b!=null) {
					playerBox--;
					collisionList.removeFirst();
				}
			}
			onScreen.removeFirst();  
		}
		
		testBox = onScreen.getLast();
		
		//checking to see if the last box onscreen is fully onscreen
		if(testBox[0].getTopSide() >= -10) {
			onScreen.add(offScreen.removeFirst());
			createOffScreenBoxes();

			for(Box x:onScreen.getLast()) {
				if(x!=null) {
					x.setY(testBox[0].getTopSide() - x.getBoxSize());
					if(x.getBoxSize() != testBox[0].getBoxSize()){
						returnValue = testBox[0].getTopSide(); //Return this value to set particle system position
					}
				}
			}
			for(Box b:onScreen.getLast()) {
				if(b!=null) {
					collisionList.add(b);  //anytime a box gets added on screen it must be added to this list.
				}
			}
			
			//Check if the added row 
		}
		return returnValue;
	}

	
	public void update(long gameTime) {
		if(mFrameTimer == -1)
    		mFrameTimer = gameTime;
    	if(gameTime > mFrameTimer + mMsPF ) {
            mFrameTimer = gameTime;
            mCurrentWallFrame +=1;
     
            if(mCurrentWallFrame >= mNumWallFrames) {
            	mCurrentWallFrame = 0;
            }
            
			for(Box[] t:onScreen) {
	    		for(Box x:t) {
	    			if(x!=null) {
	    				x.setWallFrameNumber(mCurrentWallFrame);
	    			}
	    		}
	    	}
    	}
	}
	//Function to move all onscreen boxes by a set speed.
	public void moveBoxes(int speedMult, long gameTime) {
		if(lastTime == -1) {
			lastTime = gameTime;
		}
		if(gameTime - lastTime  > 30) {
	    	for(Box[] t:onScreen) {
	    		for(Box x:t) {
	    			if(x!=null) {
	    				x.moveUp(speedMult);
	    			}
	    		}
	    	}
	    	lastTime = gameTime;
		}
	}
	
	/*
	 * creates 1 offscreen box row.
	 * function creates the random maze feature.
	 */
	public void createOffScreenBoxes() {
		Box[] test = offScreen.getLast();
		int x, y, rightside;
		x = screenSizeX/2;
		y = 0;
		rightside = 0;
		for(Box b: test) {
			if(b != null) {
				if(b.upBox) {
					x = b.getLeftSide();
					rightside = b.getRightSide();
				}
			}
		}
		
		Box startBox = new Box(x,y,curBoxSize);
		Box[] temp = offScreen.getLast(); //used as a reference for location and size
		
		//centers the starting box if the box size has changed.
		if(temp[0].getBoxSize() > startBox.getBoxSize()) {
			startBox.addToX((temp[0].getBoxSize() - startBox.getBoxSize())/2);
		} else {
			if(startBox.getRightSide()/2 > screenSizeX/2) {
				startBox.addToX((rightside - startBox.getRightSide())/2);
			}
		}
		
		//initalizes local variables
		int location = 0;
		Box[] row = new Box[5];
		row[location] = startBox;
		boolean done = false;
		double rand;
		int direction = 0; //1=right 2=left
		
		//logic for the random rows is below.
		while(!done) {
			rand = Math.random() * 10;
			if(direction == 0) {
				if(rand > 7) {
					row[location].setUpBox();
					row[location].initializeWestWall();
					row[location].initializeEastWall();
					done = true;
				} else if(rand <= 3) {
					//go right
					if(row[location].getRightSide() + startBox.getBoxSize() < screenSizeX) {
						location++;
						row[location] = new Box(row[location-1].getLeftSide()+startBox.getBoxSize(),0, startBox.getBoxSize());
						row[location-1].initializeNorthWall();
						row[location-1].initializeWestWall();
						direction = 1;
					} else {
						//go up
						done = true;
						row[location].setUpBox();
						row[location].initializeWestWall();
						row[location].initializeEastWall();
						
					}
					
				} else {
					//go left
					if(row[location].getLeftSide() - row[location].getBoxSize() > 0) {
						location++;
						row[location] = new Box(row[location-1].getLeftSide()-startBox.getBoxSize(),0, startBox.getBoxSize());
						row[location-1].initializeNorthWall();
						row[location-1].initializeEastWall();
						direction = 2;
					} else {
						//go up
						done = true;
						row[location].initializeWestWall();
						row[location].initializeEastWall();
						row[location].setUpBox();
					}					
				}
			}
			else if(direction == 1) {
				if(rand > 7) {
					if(row[location].getRightSide() + startBox.getBoxSize() < screenSizeX) {
						location++;
						row[location] = new Box(row[location-1].getLeftSide()+startBox.getBoxSize(),0, startBox.getBoxSize());
						row[location-1].initializeNorthWall();
						row[location-1].initializeSouthWall();
						//direction = 1;
					} else {
						//go up
						done = true;
						row[location].setUpBox();
						row[location].initializeSouthWall();
						row[location].initializeEastWall();
					}
				} else {
					done = true;
					row[location].setUpBox();
					row[location].initializeSouthWall();
					row[location].initializeEastWall();
				}
			}
			else {
				if(rand > 7) {
					if(row[location].getLeftSide() - startBox.getBoxSize() > 0) {
						location++;
						row[location] = new Box(row[location-1].getLeftSide()-startBox.getBoxSize(),0, startBox.getBoxSize());
						row[location-1].initializeNorthWall();
						row[location-1].initializeSouthWall();
						//direction = 2;
					} else {
						//go up
						done = true;
						row[location].setUpBox();
						row[location].initializeSouthWall();
						row[location].initializeWestWall();
					}
				} else {
					done = true;
					row[location].setUpBox();
					row[location].initializeSouthWall();
					row[location].initializeWestWall();
				}
			}
		}
		offScreen.add(row); //adds row to array.
	}
	
	/*
	 * Checks to see if the box size should have changed and then changes it.
	 * Currently based on time.
	 */
	public void checkSize(int seconds) {
		
		seconds = seconds % 60; //Need to do this because it comes in as elapsed time in seconds.
		if((seconds % 15) == 0 && !boxesChanged) {
			if(curBoxSize == SMALLEST_BOX) {
				curBoxSize = LARGEST_BOX;
			} else if(curBoxSize == SMALL_BOX) {
				curBoxSize = SMALLEST_BOX;
			} else if(curBoxSize == LARGE_BOX) {
				curBoxSize = SMALL_BOX;
			} else if(curBoxSize == LARGEST_BOX) {
				curBoxSize = LARGE_BOX;
			}
			boxesChanged = true;
		}
		
		if((seconds % 15) != 0 && boxesChanged) {
			boxesChanged = false;
		}
	}
	
	/*
	 * Player collision code...
	 * Currently fail options use system.exit which resets the program.
	 */
	public void playerCollision(Point playerPos) { 
		if(playerBox != 0 && playerBox < collisionList.size()-1) {
			if(playerPos.x >= collisionList.get(playerBox+1).getLeftSide() && playerPos.x <= collisionList.get(playerBox+1).getRightSide() 
					&& playerPos.y >= collisionList.get(playerBox+1).getTopSide() && playerPos.y <= collisionList.get(playerBox+1).getBottomSide()) {
				playerBox++;
			} else if(playerPos.x >= collisionList.get(playerBox-1).getLeftSide() && playerPos.x <= collisionList.get(playerBox-1).getRightSide() 
					&& playerPos.y >= collisionList.get(playerBox-1).getTopSide() && playerPos.y <= collisionList.get(playerBox-1).getBottomSide()) {
				playerBox--;
			} else if(playerPos.x >= collisionList.get(playerBox).getLeftSide() && playerPos.x <= collisionList.get(playerBox).getRightSide() 
					&& playerPos.y >= collisionList.get(playerBox).getTopSide() && playerPos.y <= collisionList.get(playerBox).getBottomSide()) {}
			else {
				SoundManager.getInstance();
				SoundManager.playSound(R.raw.wall_hit_sound, 1);
				SoundManager.cleanup();
				System.exit(0);
			}
		}else if(playerBox == collisionList.size()-1) {
			if(playerPos.x >= collisionList.get(playerBox-1).getLeftSide() && playerPos.x <= collisionList.get(playerBox-1).getRightSide() 
					&& playerPos.y >= collisionList.get(playerBox-1).getTopSide() && playerPos.y <= collisionList.get(playerBox-1).getBottomSide()) {
				playerBox--;
			} else if(playerPos.x >= collisionList.get(playerBox).getLeftSide() && playerPos.x <= collisionList.get(playerBox).getRightSide() 
					&& playerPos.y >= collisionList.get(playerBox).getTopSide() && playerPos.y <= collisionList.get(playerBox).getBottomSide()) {}
			else {
				SoundManager.getInstance();
				SoundManager.playSound(R.raw.wall_hit_sound, 1);
				SoundManager.cleanup();
				System.exit(0);
			}
		}else {
			if(playerPos.x >= collisionList.get(playerBox+1).getLeftSide() && playerPos.x <= collisionList.get(playerBox+1).getRightSide() 
					&& playerPos.y >= collisionList.get(playerBox+1).getTopSide() && playerPos.y <= collisionList.get(playerBox+1).getBottomSide()) {
				playerBox++;
			}else if(playerPos.y >= screenSizeY-5) {System.exit(0);} 
				else if(playerPos.x >= collisionList.get(playerBox).getLeftSide() && playerPos.x <= collisionList.get(playerBox).getRightSide() 
					&& playerPos.y >= collisionList.get(playerBox).getTopSide() && playerPos.y <= collisionList.get(playerBox).getBottomSide()) {
				
			} else {
				SoundManager.getInstance();
				SoundManager.playSound(R.raw.wall_hit_sound, 1);
				SoundManager.cleanup();
				System.exit(0);
			}
		}
	}
	
	public void draw(GL10 gl) {
		for(Box[] boxStrip:onScreen) {
    		for(Box box:boxStrip) {
    			if(box!=null) {
    				box.draw(gl);
    			}
    		}
    	}
	}
}
